/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pkgMetodoPyramid.pkgPresentacion;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import org.apache.poi.hssf.record.formula.eval.ConcatEval;
import pkgMetodoPyramid.pkgNegocio.EntityPyramid;
import pkgMetodoPyramid.pkgSoporte.Constants;
import pkgUtil.Util;

/**
 *
 * @author Administrador
 */
public class PyramidTableModel extends AbstractTableModel {

    public static final int col_edad = 0;
    public static final int col_varones = 1;
    public static final int col_mujeres = 2;
    public static final int col_porc_varones = 3;
    public static final int col_porc_mujeres = 4;
    public static final int col_porc_vtotal = 5;
    public static final int col_porc_mtotal = 6;
    public static final int cant_col = 7;
    private boolean cellEditable = true;
    private LinkedList listeners = new LinkedList();
    private String[] columnNames = {"Edad",
        "Varones",
        "Mujeres",
        "% Varones",
        "% Mujeres",
        "% Varones s/Total",
        "% Mujeres s/Total"};
    //private Object[][] data = new Object[0][7];
    private ArrayList lstData = new ArrayList();
    private EntityPyramid lastEntityPyramid = null;
    private int indexRowMinGrupoAbierto = -1;

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public int getRowCount() {
        return lstData.size();
    }

    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    @Override
    public Object getValueAt(int row, int col) {
        try {
            EntityPyramid entity = (EntityPyramid) lstData.get(row);
            if (entity == null) {
                return null;
            }
            switch (col) {
                case col_edad:
                    return entity.getEdad();
                case col_varones:
                    return entity.getVarones();
                case col_mujeres:
                    return entity.getMujeres();
                case col_porc_varones:
                    return entity.getPorc_varones();
                case col_porc_mujeres:
                    return entity.getPorc_mujers();
                case col_porc_vtotal:
                    return entity.getPorc_vtotal();
                case col_porc_mtotal:
                    return entity.getPorc_mtotal();
                default:
                    return null;
            }
        } catch (Exception ex) {
            System.out.println("ERROR EN getValueAt: " + ex.getMessage());
        }
        return null;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        try {
            EntityPyramid entity = (EntityPyramid) lstData.get(row);
            if (entity == null) {
                return;
            }
            Object valueValidated = validValue(value, col);

            switch (col) {
                case col_edad:
                    entity.setEdad(String.valueOf(valueValidated));
                    break;
                case col_varones:
                    entity.setVarones(valueValidated != null ? (Integer) valueValidated : null);
                    break;
                case col_mujeres:
                    entity.setMujeres(valueValidated != null ? (Integer) valueValidated : null);
                    break;
                case col_porc_varones:
                    Double pv_formatted = formatDoubleValue((Double) valueValidated);
                    entity.setPorc_varones(valueValidated != null ? pv_formatted : null);
                    break;
                case col_porc_mujeres:
                    Double pm_formatted = formatDoubleValue((Double) valueValidated);
                    entity.setPorc_mujers(valueValidated != null ? pm_formatted : null);
                    break;
                case col_porc_vtotal:
                    Double pvt_formatted = formatDoubleValue((Double) valueValidated);
                    entity.setPorc_vtotal(valueValidated != null ? pvt_formatted : null);
                    break;
                case col_porc_mtotal:
                    Double pmt_formatted = formatDoubleValue((Double) valueValidated);
                    entity.setPorc_mtotal(valueValidated != null ? pmt_formatted : null);
                    break;
            }

        } catch (Exception ex) {
            System.out.println("ERROR EN setValueAt: " + ex.getMessage());
        }

        // Avisa a los suscriptores del cambio, creando un TableModelEvent ...
        TableModelEvent evento = new TableModelEvent(this, row, row,
                col);

        // ... y pasándoselo a los suscriptores.
        avisaSuscriptores(evento);
    }

    private Double formatDoubleValue(Double value) {
        if (value == null) {
            return null;
        }
        Double v_formatted = Util.redondear(value.doubleValue(), Constants.CANTIDAD_DECIMALES);
        return v_formatted;
    }

    private Object validValue(Object value, int col) {
        try {
            switch (col) {
                case col_edad:
                    return value;
                case col_varones:

                    //Integer intVaronesValue = (Integer) value;
                    String cadVarones = String.valueOf(value);
                    Integer intVaronesValue = Integer.valueOf(cadVarones.trim());
                    if (intVaronesValue == null || intVaronesValue.intValue() < 0) {
                        intVaronesValue = new Integer("0");
                    }
                    return intVaronesValue;
                case col_mujeres:
                    //Integer intMuejeresValue = (Integer) value;
                    String cadMujeres = String.valueOf(value);
                    Integer intMujeresValue = Integer.valueOf(cadMujeres.trim());
                    if (intMujeresValue == null || intMujeresValue.intValue() < 0) {
                        intMujeresValue = new Integer("0");
                    }
                    return intMujeresValue;
                case col_porc_varones:
                    Double douPorcVaronesValue = (Double) value;

                    if (douPorcVaronesValue == null || douPorcVaronesValue.doubleValue() < 0) {
                        douPorcVaronesValue = new Double("0");
                    }
                    return douPorcVaronesValue;
                case col_porc_mujeres:
                    Double douPorcMujeresValue = (Double) value;

                    if (douPorcMujeresValue == null || douPorcMujeresValue.doubleValue() < 0) {
                        douPorcMujeresValue = new Double("0");
                    }
                    return douPorcMujeresValue;
                case col_porc_vtotal:
                    Double douPorcTotalVaronesValue = (Double) value;

                    if (douPorcTotalVaronesValue == null || douPorcTotalVaronesValue.doubleValue() < 0) {
                        douPorcTotalVaronesValue = new Double("0");
                    }
                    return douPorcTotalVaronesValue;
                case col_porc_mtotal:
                    Double douPorcTotalMujeresValue = (Double) value;

                    if (douPorcTotalMujeresValue == null || douPorcTotalMujeresValue.doubleValue() < 0) {
                        douPorcTotalMujeresValue = new Double("0");
                    }
                    return douPorcTotalMujeresValue;
                default:
                    return null;
            }
        } catch (Exception ex) {
            return null;
        }


    }

    public void setNumRows(int cantRow) {
        try {
            int old = getRowCount();
            if (old == cantRow || cantRow == 0) {
                return;
            }
            if (cantRow < old) {
                int indexFrom = cantRow;
                this.removeFromIndex(indexFrom);
            } else {

                for (int i = 0; i < (cantRow - old); i++) {
                    this.addEntityPyramid(getNextEntityPyramid());
                }
            }

        } catch (Exception ex) {
            System.out.println("Error en metodo setNumRows(): " + ex.getMessage());
        }
    }

    public void addEntityPyramid(EntityPyramid entityPyramid) {
        lstData.add(entityPyramid);
        setLastEntityPyramid(entityPyramid);

        // Avisa a los suscriptores creando un TableModelEvent...
        TableModelEvent evento;
        evento = new TableModelEvent(this, this.getRowCount() - 1,
                this.getRowCount() - 1, TableModelEvent.ALL_COLUMNS,
                TableModelEvent.INSERT);
        avisaSuscriptores(evento);

    }

    public void updateEntityPyramid(EntityPyramid p, int indexRow) throws Exception {
        if (!isValidIndexRow(indexRow)) {
            throw new Exception("IndexRow fuera de rango admitido");
        }
        lstData.set(indexRow, p);
        // Avisa a los suscriptores creando un TableModelEvent...
        TableModelEvent evento;
        evento = new TableModelEvent(this, indexRow,
                indexRow, TableModelEvent.ALL_COLUMNS,
                TableModelEvent.UPDATE);
        avisaSuscriptores(evento);
    }

    public void removeFromIndex(int indexRowBegin) {
        int indexTo = indexRowBegin + ((lstData.size() - 1) - indexRowBegin);

        for (int i = indexTo; i >= indexRowBegin; i--) {
            removeRow(i);
        }

    }

    public EntityPyramid removeRow(int indexRow) {
        EntityPyramid entity = null;
        // Se borra la fila
        entity = (EntityPyramid) lstData.remove(indexRow);

        // Y se avisa a los suscriptores, creando un TableModelEvent...
        TableModelEvent evento = new TableModelEvent(this, indexRow, indexRow,
                TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE);

        // ... y pasándoselo a los suscriptores
        avisaSuscriptores(evento);

        return entity;

    }

    @Override
    public void addTableModelListener(TableModelListener l) {
        listeners.add(l);
    }

    @Override
    public void removeTableModelListener(TableModelListener l) {
        listeners.remove(l);
    }

    private void avisaSuscriptores(TableModelEvent evento) {
        int i;

        // Bucle para todos los suscriptores en la lista, se llama al metodo
        // tableChanged() de los mismos, pasándole el evento.
        for (i = 0; i < listeners.size(); i++) {
            ((TableModelListener) listeners.get(i)).tableChanged(evento);
        }
    }

    /*
     * JTable uses this method to determine the default renderer/ editor for
     * each cell. If we didn't implement this method, then the last column would
     * contain text ("true"/"false"), rather than a check box.
     */
    @Override
    public Class getColumnClass(int c) {
        try {
            switch (c) {
                case col_edad:
                    return String.class;
                case col_varones:
                    return Integer.class;
                case col_mujeres:
                    return Integer.class;
                case col_porc_varones:
                    return Double.class;
                case col_porc_mujeres:
                    return Double.class;
                case col_porc_vtotal:
                    return Double.class;
                case col_porc_mtotal:
                    return Double.class;
            }
            return Object.class;
        } catch (Exception ex) {
            System.out.println("ERROR EN getColumnClass: " + ex.getMessage());
            return Object.class;
        }
    }

    /*
     * Don't need to implement this method unless your table's editable.
     */
    @Override
    public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        switch (col) {
            case col_edad:
                return false;
            case col_varones:
                return getStatusCellEditable();
            case col_mujeres:
                return getStatusCellEditable();
            case col_porc_varones:
                return false;
            case col_porc_mujeres:
                return false;
            case col_porc_vtotal:
                return false;
            case col_porc_mtotal:
                return false;
        }
        return false;
    }

    public void setEntityPyramid(EntityPyramid p, int indexRow) throws Exception {
        if (!isValidIndexRow(indexRow)) {
            throw new Exception("IndexRow fuera de rango admitido");
        }
        lstData.set(indexRow, p);
    }

    public EntityPyramid getEntityPyramed(int indexRow) throws Exception {

        if (!isValidIndexRow(indexRow)) {
            throw new Exception("IndexRow fuera de rango admitido");
        }

        EntityPyramid entity = (EntityPyramid) lstData.get(indexRow);

        return entity;
    }

    /**
     * @return the indexRowMinGrupoAbierto
     */
    public int getIndexRowMinGrupoAbierto() {
        return indexRowMinGrupoAbierto;
    }

    /**
     * @param indexRowMinGrupoAbierto the indexRowMinGrupoAbierto to set
     */
    public void setIndexRowMinGrupoAbierto(int indexRowMinGrupoAbierto) {
        this.indexRowMinGrupoAbierto = indexRowMinGrupoAbierto;
    }

    public int getIndexLastRow() {
        return (getRowCount() - 1);
    }

    public int getIndexLastColumn() {
        return (getColumnCount() - 1);
    }

    public boolean isValidIndexRow(int indexRow) {
        if (indexRow < 0 || indexRow > getIndexLastRow()) {
            return false;
        }
        return true;
    }

    public boolean isValidIndexColumn(int indexColumn) {
        if (indexColumn < 0 || indexColumn > getIndexLastColumn()) {
            return false;
        }
        return true;
    }

    public EntityPyramid getNextEntityPyramid() {
        if (getLastEntityPyramid() == null || getLastEntityPyramid().getEdad() == null) {
            return new EntityPyramid();
        }
        return new EntityPyramid(getLastEntityPyramid().formatProxGrupo());
    }

    /**
     * @return the lastEntityPyramid
     */
    public EntityPyramid getLastEntityPyramid() {
        return lastEntityPyramid;
    }

    /**
     * @param lastEntityPyramid the lastEntityPyramid to set
     */
    public void setLastEntityPyramid(EntityPyramid lastEntityPyramid) {
        this.lastEntityPyramid = lastEntityPyramid;
    }

    public Double sumarize(int indexColumn) throws Exception {
        if (!isValidIndexColumn(indexColumn)) {
            throw new Exception("Indice no válido para columna");
        }
        int cantRow = getRowCount();
        Double total = new Double("0");
        for (int i = 0; i < cantRow; i++) {
            Object objValue = getValueAt(i, indexColumn);
            if (objValue != null) {
                Double douValue = Double.valueOf(String.valueOf(objValue));
                total = total + douValue;
            }
        }
        return total;
    }

    public boolean isColumnVarones(int indexColumn) {
        if (indexColumn == col_varones) {
            return true;
        }
        return false;
    }

    public boolean isColumnMujeres(int indexColumn) {
        if (indexColumn == col_mujeres) {
            return true;
        }
        return false;
    }

    public Iterator getIteratorData() {
        if (lstData == null) {
            return null;
        }
        return lstData.iterator();
    }

    public int getIndexOf(EntityPyramid entity) {
        return lstData.indexOf(entity);
    }

    /**
     * @return the cellEditable
     */
    public boolean getStatusCellEditable() {
        return cellEditable;
    }

    /**
     * @param cellEditable the cellEditable to set
     */
    public void setCellEditable(boolean cellEditable) {
        this.cellEditable = cellEditable;
    }
}
